using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace Labirinto_Magico
{
    public enum LOAD_FROM
    {
        None,
        File,
        Temporary
    }

    public class GameLogic : Microsoft.Xna.Framework.DrawableGameComponent
    {
        GameGUIHandler mGUI;
        GameGuiRender mGUIRender;

        GameRender mRender;
        SoundHandler mSound;

        LOAD_FROM mToLoad;
        SI.LOGIC_GAME_STATE mState = SI.LOGIC_GAME_STATE.N;

        int mNumPlayers;

        public GameLogic(Game game, LOAD_FROM toLoad, int iPlayers)
            : base(game)
        {
            //mGameState = new GameState();
            mToLoad = toLoad;

//             mFirstTurnHandler = new FirstTurnPartHandler();
//             mSecondTurnHandler = new SecondTurnPartHandler();

            mNumPlayers = iPlayers;
        }

        public override void Initialize()
        {
            if (mToLoad == LOAD_FROM.None)
                LabyrinthGameState.gameState = LabyrinthGameState.State.Init(mNumPlayers, 3, Game.GraphicsDevice.Viewport.Height * 0.111111f);
            else
                LoadGame();

            RenderingData renderWrapper = (RenderingData)Game.Services.GetService(typeof(RenderingData));
            mSound = (SoundHandler)Game.Services.GetService(typeof(SoundHandler));

            mRender = new GameRender(renderWrapper);

            if (mToLoad == LOAD_FROM.None)
                for (int i = 0; i < LabyrinthGameState.gameState.mPlayers.Length; ++i)
                    {
                        Player.Player p = LabyrinthGameState.gameState.mPlayers.ElementAt(i);
                        p.mGoal = GameLogicFunctions.GetNextGoal(p.mPosition, p);
                    }

            mSound.StartSound();
            mGUI = new GameGUIHandler();
            mGUI.InitGUI(Game, LabyrinthGameState.gameState, Game.GraphicsDevice.Viewport.Height * 0.111111f, LabyrinthGameState.gameState.mRemainedTile, Game.GraphicsDevice.Viewport.Width, Game.GraphicsDevice.Viewport.Height);
            mGUIRender = new GameGuiRender(renderWrapper, Game.GraphicsDevice.Viewport);

            base.Initialize();
        }

        public override void Update(GameTime gameTime)
        {
            if (mGUI.mPause.PressButton())
            {
                mSound.ButtonSound();
                SaveTemporaryGame();
                Game.Components.Remove(this);
                Game.Components.Add(new PauseMenu(Game));
            }
            else
                LogicUpdate(gameTime);

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            mRender.DrawChessboard(mState, LabyrinthGameState.gameState.mSelectedTile, LabyrinthGameState.gameState.mRemainedTile);

            mRender.DrawPlayers(GraphicsDevice.Viewport);

            mGUIRender.DrawCPs(mGUI.mChessboard.mControlPoints);
            mGUIRender.DrawScore(LabyrinthGameState.gameState.mSelectedPlayer, mGUI.mScore);
            mGUIRender.DrawButton(mGUI.mPause);

            if (mState == SI.LOGIC_GAME_STATE.N)
                mGUIRender.DrawNextTurn(LabyrinthGameState.gameState.mSelectedPlayer, mGUI.mTurnAndVictory);

            if (LabyrinthGameState.gameState.mWinner)
                mGUIRender.DrawVictory(LabyrinthGameState.gameState.mSelectedPlayer, mGUI.mTurnAndVictory);

            base.Draw(gameTime);
        }

        public void LogicUpdate(GameTime gameTime)
        {
            if (LabyrinthGameState.gameState.mWinner)
            {
                if (mGUI.mTurnAndVictory.TimePassed(gameTime.TotalGameTime, 10))
                {
                    Game.Components.Remove(this);
                    Game.Components.Add(new MainMenu(Game));
                    this.Dispose();
                }
            }
            else
            {
                switch (mState)
                {
                case SI.LOGIC_GAME_STATE.N:
                    if (NextTurn(gameTime.TotalGameTime))
                        mState = SI.LOGIC_GAME_STATE.RI;
            	    break;
                case SI.LOGIC_GAME_STATE.RI:
                    if (mGUI.mChessboard.mRemainedTile.PressButton())
                    {
                        GameLogicFunctions.RotateRemainedTile();
                        mSound.ButtonSound();
                    }
                    GUICPButton cpButton1 = mGUI.mChessboard.UpdateCPButton(gameTime);
                    if (cpButton1 != null)
                    {
                        SI.POSITION insertPos = cpButton1.mType;
                        int sequencePos = cpButton1.mSequencePosition;
                        GameLogicFunctions.InsertTile(insertPos, sequencePos);
                        mGUI.mChessboard.UpdateAssociatedTiles();
                        mSound.SliderSound();

                        mState = SI.LOGIC_GAME_STATE.P;
                    }
            	    break;
                case SI.LOGIC_GAME_STATE.P:
                    GUIChessboardButton selectedTile = mGUI.mChessboard.UpdateSelectedTile(gameTime);
                    if (selectedTile != null)
                    {
                        if (LabyrinthGameState.gameState.mSelectedPlayer.mPathFinder.IsTileInTree(selectedTile.mAssociatedTile))
                        {
                            mSound.ButtonSound();
                            LabyrinthGameState.gameState.mSelectedTile = selectedTile.mAssociatedTile;
                            mState = SI.LOGIC_GAME_STATE.M;
                        }
                        else
                            mSound.ErrorSound();
                    }
                    else
                        GameLogicFunctions.UpdatePathFindingToGoal();
            	    break;
                case SI.LOGIC_GAME_STATE.M:
                    if (GameLogicFunctions.UpdateMoveToGoal(gameTime, LabyrinthGameState.gameState.mSelectedTile))
                    {
                        if (LabyrinthGameState.gameState.mWinner)
                            mSound.VictorySound();
                        mState = SI.LOGIC_GAME_STATE.N;
                    }
            	    break;
                }
            }
        }

        public bool NextTurn(TimeSpan iTime)
        {
            if (mGUI.mTurnAndVictory.TimePassed(iTime, 2))
            {
                return true;
            }
            else
                return false;
        }

        void SaveTemporaryGame()
        {
            using (var stream = File.Open("tempgame.sav", FileMode.Create))
            {
                var binary_formatter = new BinaryFormatter();
                binary_formatter.Serialize(stream, LabyrinthGameState.gameState);
                binary_formatter.Serialize(stream, mState);
                stream.Close();
            }
        }

        void LoadGame()
        {
            String fileName;

            if (mToLoad == LOAD_FROM.File)
                fileName = "savegame.sav";
            else
                fileName = "tempgame.sav";
            if (File.Exists(fileName))
            {
                using (var stream = File.Open(fileName, FileMode.Open))
                {
                    var binary_formatter = new BinaryFormatter();
                    LabyrinthGameState.gameState = (LabyrinthGameState.State)binary_formatter.Deserialize(stream);
                    mState = (SI.LOGIC_GAME_STATE)binary_formatter.Deserialize(stream);
                    stream.Close();
                }
            }
        }
    }
}
